package com.telecom.weixi.view;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class LockPatternView2 extends View {
	public static final int CORE_COLOR = -1;
	public static final int CORRECT_COLOR = -15658497;
	public static final int FIRST_SELECTED_COLOR = -16720436;
	public static final int INCORRECT_COLOR = -2289391;
	public static final double INNER_SIZE_RATIO = 0.33D;
	public static final int MANTLE_COLOR = -16777216;
	public static final double MIDDLE_SIZE_RATIO = 0.9D;
	public static final double OUTER_SIZE_RATIO = 0.75D;
	public static final int PATH_COLOR = -3355444;
	public static final int SELECTED_COLOR = -16720640;
	public static final int UNSELECTED_COLOR = -6710887;
	private int activeColor = -16720640;
	private int arrowBaseHalfLength;
	private int arrowBaseRadius;
	private Paint arrowPaint;
	private int arrowPointRadius;
	private LinkedList<Path> arrows;
	private int displayDelay = 1000;
	private Paint firstArrowPaint;
	private int gridLength = 0;
	private int gridSize = 3;
	private Handler handler = new Handler();
	private boolean highlightFirst = false;
	private ShapeDrawable[] innerCircles;
	private int innerDiameter;
	private int innerOffset;
	private ShapeDrawable[] middleCircles;
	private int middleDiameter;
	private int middleOffset;
	private Queue<Integer> normalPath = new LinkedList();
	private ShapeDrawable[] outerCircles;
	private int outerDiameter;
	private int outerOffset;
	private LinkedList<Integer> pathOrder = new LinkedList();
	private Paint pathPaint = new Paint();
	private LinkedList<Point> pathPoints = new LinkedList();
//	private boolean practiceMode = false;
	private boolean practiceMode = true;
	private Queue<Integer> practicePath = new LinkedList();
	private final ScheduledExecutorService scheduler = Executors
			.newScheduledThreadPool(1);
	private boolean showingResult = false;
	private int wildX = -1;
	private int wildY = -1;
	private boolean bInit = true;
  
	public interface ICheckConfrim{
		public void onLockPattern(boolean bInit, boolean matched);
	};
	ICheckConfrim checkConfrim;
	Activity uiActivity;
	
	public LockPatternView2(Context paramContext, AttributeSet paramAttributeSet) {
		super(paramContext, paramAttributeSet);
		this.pathPaint.setColor(-3355444);
	    this.firstArrowPaint = new Paint();
	    this.firstArrowPaint.setColor(-16720436);
	    this.firstArrowPaint.setStyle(Paint.Style.FILL);
	    this.arrowPaint = new Paint();
	    this.arrowPaint.setColor(this.activeColor);
	    this.arrowPaint.setStyle(Paint.Style.FILL);
//	    Debug("constructor");
	    updateDrawableNodes();
	}

	public void setCheckConfirmListener(ICheckConfrim listener, Activity activity){
		uiActivity = activity;
		checkConfrim = listener;
	}
	
	private void updatePath(Queue<Integer> paramQueue) {
		
		this.pathOrder = new LinkedList();
		this.pathPoints = new LinkedList();
		Iterator<Integer> localIterator1 = paramQueue.iterator();
		this.arrowPaint.setColor(this.activeColor);
		ShapeDrawable[] arrayOfShapeDrawable = this.outerCircles;
		int n = arrayOfShapeDrawable.length;
//		Debug("updatePath path: " + paramQueue.size() + " outCircles: " + outerCircles.length);
//		int k;
		int k=0;
		for (int index = 0;;index++) {
//			Debug("for index=" + index);
			int m;
			if (index >= n) {
//				Debug("if " +index + ">=" + n); 
//				int j;
//				if (localIterator1.hasNext()) {
//					j = localIterator1.next().intValue();
//					if ((!this.highlightFirst) || (this.practiceMode))
//						this.outerCircles[j].getPaint().setColor(
//								this.activeColor);
//					else
//						this.outerCircles[j].getPaint().setColor(-16720436);
//					this.pathOrder.offer(new Integer(j));
//				}
				while (true) {
					int i;
					if (!localIterator1.hasNext()) {
						i = 0;
						Iterator<Integer> localIterator2 = paramQueue.iterator();
						if (paramQueue.size() > 0) {
							n = localIterator2.next().intValue();
							m = n % this.gridSize * this.gridLength / this.gridSize 
									+ this.gridLength / (2 * this.gridSize);
							n = n / this.gridSize * this.gridLength / this.gridSize 
									+ this.gridLength / (2 * this.gridSize);
							this.pathPoints.offer(new Point(m, n));
							if (localIterator2.hasNext()) {
								i = (localIterator2.next())
										.intValue();
								n = i % this.gridSize * this.gridLength / this.gridSize 
										+ this.gridLength / (2 * this.gridSize);
								m = i / this.gridSize * this.gridLength / this.gridSize 
										+ this.gridLength / (2 * this.gridSize);
								this.pathPoints.offer(new Point(n, m));
							}
						}
						while (true) {
							if (!localIterator2.hasNext()) {
								invalidate();
								return;
							}
							n = i;
							i = localIterator2.next().intValue();
							m = n % this.gridSize * this.gridLength / this.gridSize 
									+ this.gridLength / (2 * this.gridSize);
							int i2 = n / this.gridSize * this.gridLength / this.gridSize 
									+ this.gridLength / (2 * this.gridSize);
							n = i % this.gridSize * this.gridLength / this.gridSize 
									+ this.gridLength / (2 * this.gridSize);
							int i1 = i / this.gridSize * this.gridLength / this.gridSize 
									+ this.gridLength / (2 * this.gridSize);
							this.pathPoints.offer(new Point(m, i2));
							this.pathPoints.offer(new Point(n, i1));
						}
					}
//					k = ((Integer) i.next()).intValue();
					k = localIterator1.next().intValue();
					this.outerCircles[k].getPaint().setColor(this.activeColor);
					this.pathOrder.offer(new Integer(k));
				}
			}
			outerCircles[k].getPaint().setColor(-6710887);
//			outerCircles[index].getPaint().setColor(Color.GREEN);
		}
	}

	public int getGridSize() {
		return this.gridSize;
	}

	@Override
	protected void onDraw(Canvas paramCanvas) {
		// TODO Auto-generated method stub
		super.onDraw(paramCanvas);
//		Debug("2. onDraw...");
		Iterator localIterator = this.pathPoints.iterator();
	    this.arrows = new LinkedList();
	    while (true)
	    {
//	    	Debug("2.1 while...");
//	    	Debug("draw pathPoints: " + pathPoints.size() + " outer: " + outerCircles.length 
//	    			+ " mid: " + middleCircles.length + " inner: " + innerCircles.length);
	      if (!localIterator.hasNext())
	      {
//	    	  Debug("2.2 localIterator.hasNext");
	        ShapeDrawable[] arrayOfShapeDrawable2 = this.outerCircles;
	        int i = arrayOfShapeDrawable2.length;
	        ShapeDrawable[] arrayOfShapeDrawable1;
//	        for (int j = 0; ;arrayOfShapeDrawable1++)
	        for (int j = 0; ;j++)
	        {
//	        	Debug("2.3 j==" + j);
//	          int k;
	          int k = 0;
	          if (j >= i)
	          {
	            arrayOfShapeDrawable1 = this.middleCircles;
	            i = arrayOfShapeDrawable1.length;
	            for (k = 0; ; k++)
	            {
//	            	Debug("2.4 k==" + k);
	              if (k >= i)
	              {
	                arrayOfShapeDrawable1 = this.innerCircles;
	                k = arrayOfShapeDrawable1.length;
	                for (i = 0; ; i++)
	                {
	                  if (i >= k)
	                    for (i = 0; ; i++)
	                    {
	                      if (i >= this.arrows.size()){
//	                    	  Debug("return ");
	                        return;
	                      }
	                      if ((i != 0) || (!this.highlightFirst) || (this.practiceMode))
	                        paramCanvas.drawPath((Path)this.arrows.get(i), this.arrowPaint);
	                      else
	                        paramCanvas.drawPath((Path)this.arrows.get(i), this.firstArrowPaint);
	                    }
	                  arrayOfShapeDrawable1[i].draw(paramCanvas);
	                }
	              }
	              arrayOfShapeDrawable1[k].draw(paramCanvas);
	            }
	          }
//	          k[arrayOfShapeDrawable1].draw(paramCanvas);
	          outerCircles[j].draw(paramCanvas);
	        }
	      }
	      Point localPoint1 = (Point)localIterator.next();
	      if (!localIterator.hasNext())
	      {
	        if ((this.wildX < 0) || (this.wildY < 0))
	          continue;
	        paramCanvas.drawLine(localPoint1.x, localPoint1.y, this.wildX, this.wildY, this.pathPaint);
	        continue;
	      }
	      Point localPoint2 = (Point)localIterator.next();
	      double d = Math.atan2(localPoint1.y - localPoint2.y, localPoint1.x - localPoint2.x);
	      float f4 = localPoint1.x - (float)(Math.cos(d) * this.arrowPointRadius);
	      float f3 = localPoint1.y - (float)(Math.sin(d) * this.arrowPointRadius);
	      float f1 = localPoint1.x - (float)(Math.cos(d) * this.arrowBaseRadius);
	      float f2 = localPoint1.y - (float)(Math.sin(d) * this.arrowBaseRadius);
	      Path localPath = new Path();
	      localPath.moveTo(f4, f3);
	      localPath.lineTo(f1 - (float)(this.arrowBaseHalfLength * Math.cos(1.570796326794897D + d)), f2 - (float)(this.arrowBaseHalfLength * Math.sin(1.570796326794897D + d)));
	      localPath.lineTo(f1 - (float)(this.arrowBaseHalfLength * Math.cos(d - 1.570796326794897D)), f2 - (float)(this.arrowBaseHalfLength * Math.sin(d - 1.570796326794897D)));
	      localPath.lineTo(f4, f3);
	      this.arrows.offer(localPath);
	      paramCanvas.drawLine(localPoint1.x, localPoint1.y, localPoint2.x, localPoint2.y, this.pathPaint);
	      if ((localIterator.hasNext()) || (this.wildX < 0) || (this.wildY < 0))
	        continue;
	      paramCanvas.drawLine(localPoint2.x, localPoint2.y, this.wildX, this.wildY, this.pathPaint);
	    }
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int j = View.MeasureSpec.getSize(widthMeasureSpec);
	    int i = View.MeasureSpec.getSize(heightMeasureSpec);
	    int k = Math.min(j, i);
	    if (j != 0)
	    {
	      if (i == 0)
	        k = j;
	    }
	    else
	      k = i;
	    this.gridLength = k;
//	    Debug("measure: k=" + k);
	    setMeasuredDimension(k, k);
	}

	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		// TODO Auto-generated method stub
		super.onSizeChanged(w, h, oldw, oldh);
		this.outerDiameter = (int)(0.75D * (this.gridLength / this.gridSize));
	    this.middleDiameter = (int)(0.9D * this.outerDiameter);
	    this.innerDiameter = (int)(0.33D * this.outerDiameter);
	    this.outerOffset = (this.gridLength / (2 * this.gridSize) - this.outerDiameter / 2);
	    this.middleOffset = (this.gridLength / (2 * this.gridSize) - this.middleDiameter / 2);
	    this.innerOffset = (this.gridLength / (2 * this.gridSize) - this.innerDiameter / 2);
	    this.arrowPointRadius = (int)(0.9D * (this.middleDiameter / 2.0D));
	    this.arrowBaseRadius = (int)(0.6D * (this.middleDiameter / 2.0D));
	    this.arrowBaseHalfLength = (int)(0.3D * (this.middleDiameter / 2.0D));
	    updateDrawableNodes();
	    invalidate();
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
//		Debug("onTouchEvent...");
//		return super.onTouchEvent(event);
		int j;
	    if (this.practiceMode)
	    {
	      switch (event.getAction())
	      {
	      case MotionEvent.ACTION_DOWN:
	        this.showingResult = false;
	        this.practicePath = new LinkedList();
	        this.activeColor = -16720640;
	        
	        updatePath(this.practicePath);
	      case MotionEvent.ACTION_MOVE:
	        float offX = event.getX();
	        float offY = event.getY();
	        this.wildX = (int)offX;
	        this.wildY = (int)offY;
	        int i1 = this.gridLength / this.gridSize;
	        int k = (int)offX / i1;
	        if (k >= this.gridSize)
	          k = -1 + this.gridSize;
	        int m = (int)offY / i1;
	        if (m >= this.gridSize)
	          m = -1 + this.gridSize;
	        int n = (int)((0.5D + k) * i1);
	        i1 = (int)((0.5D + m) * i1);
	        if ((int)Math.sqrt(Math.pow(offX - n, 2.0D) + Math.pow(offY - i1, 2.0D)) <= this.middleDiameter / 2)
	        {
	          j = k + m * this.gridSize;
//	          if (!this.practicePath.contains(Integer.valueOf(j)));
	          if (!this.practicePath.contains(Integer.valueOf(j))){
	        	  this.practicePath.offer(Integer.valueOf(j));
	  	          updatePath(this.practicePath);
//	  	          j = 1;
	          }
	        }
	        else
	        {
	          invalidate();
	          break;
	        }
//	        this.practicePath.offer(Integer.valueOf(j));
//	        updatePath(this.practicePath);
//	        j = 1;
	        break;
	      case MotionEvent.ACTION_UP:
	        this.wildX = -1;
	        this.wildY = -1;
	        if (this.practicePath.size() == 0)
//	          break label379;
	        	break;
	        if(bInit){
	        	this.activeColor = -16720640;
	        }else if (this.practicePath.equals(this.normalPath)){
	          this.activeColor = -15658497;
	        }
	        else{
		          this.activeColor = -2289391;
	        }
	        updatePath(this.practicePath);
	        this.showingResult = true;
	        this.scheduler.schedule(new Runnable()
	        {
	          public void run()
	          {
	            LockPatternView2.this.handler.post(new Runnable()
	            {
	              public void run()
	              {
	                if (LockPatternView2.this.showingResult)
	                {
//	                	Debug("schedule show result");
//	                  LockPatternView.access$102(LockPatternView.this, -16720640);
//	                  LockPatternView.access$002(LockPatternView.this, false);
//	                  LockPatternView.access$202(LockPatternView.this, new LinkedList());
	                  LockPatternView2.this.updatePath(LockPatternView2.this.practicePath);
	                  practiceMode = false;
	                  if(uiActivity != null){
	                	  uiActivity.runOnUiThread(new Runnable() {
								
								@Override
								public void run() {
									// TODO Auto-generated method stub
									 if(checkConfrim != null){
										 checkConfrim.onLockPattern(bInit, practicePath.equals(normalPath));
										}
								};
		                  });
	                  }
	                }
	              }
	            });
	          }
	        }
	        , this.displayDelay, TimeUnit.MILLISECONDS);
	      default:
		        int i = 0;
		        break;
	      }
	      j = 1;
//	      break label386;
//	      label379: j = 1;
	      return true;
	    }
	    else
	    {
	    	return false;
	    }
//	    label386: return j;
//		return true;
	}
	
	void resetGraphData(){
		for (int index = 0; index < outerCircles.length;index++) {
			outerCircles[index].getPaint().setColor(-6710887);
		}
	}
	
	 public void refreshPath()
	  {
	    updatePath(this.pathOrder);
	  }

	  public void setGridSize(int paramInt)
	  {
	    this.gridSize = paramInt;
	    updateDrawableNodes();
	  }

	  public void setHighlight(boolean paramBoolean)
	  {
	    this.highlightFirst = paramBoolean;
	  }

	  public void setPath(Queue<Integer> paramQueue)
	  {
		  this.normalPath = paramQueue;
		   if (!this.practiceMode)
		    updatePath(this.normalPath);
	  }
	  public void setPracticeMode(boolean paramBoolean)
	  {
		  this.practiceMode = paramBoolean;
//		    if (this.practiceMode)
//		    {
//		      updatePath(this.practicePath);
//		    }
//		    else
//		    {
//		      this.activeColor = -16720640;
//		      updatePath(this.normalPath);
//		      this.showingResult = false;
//		      this.practicePath = new LinkedList();
//		    }
	  }

	  private void recordPath(Queue<Integer> paramQueue)
	  {
		  this.normalPath = paramQueue;
	  }
	  
	  public void nextStep(boolean record){
//		  Debug("nextStep " + record);
		  bInit = false;
		  if(record){
			  recordPath(practicePath);
		  }
		  resetState();
	  }
	  
	  public void resetState(){
		  this.practiceMode = true;
		  resetGraphData();
	      this.showingResult = false;
	      this.practicePath = new LinkedList();
	      updatePath(this.practicePath);
	  }
	  
	  public String getPathWord(){
		  String ret = "";
		  Iterator<Integer> iterator = practicePath.iterator();
		  while(iterator.hasNext()){
			  ret += iterator.next().intValue() + 1;
		  }
		  return ret;
	  }
	public void updateDrawableNodes() {
//		Debug("1. updateDrawableNodes... gridLength: " + gridLength + " gridSize: " + gridSize);
		this.outerCircles = new ShapeDrawable[this.gridSize * this.gridSize];
		this.middleCircles = new ShapeDrawable[this.gridSize * this.gridSize];
		this.innerCircles = new ShapeDrawable[this.gridSize * this.gridSize];
		for (int i = 0; ; i++) {
//			Debug("for index: " + i);
			
			if (i >= this.gridSize * this.gridSize) {
//				Debug("if " + i + " >= " + (gridSize * gridSize));
				this.outerDiameter = (int) (0.75D * (this.gridLength / this.gridSize));
				this.middleDiameter = (int) (0.9D * this.outerDiameter);
				this.innerDiameter = (int) (0.33D * this.outerDiameter);
				this.outerOffset = (this.gridLength / (2 * this.gridSize) - this.outerDiameter / 2);
				this.middleOffset = (this.gridLength / (2 * this.gridSize) - this.middleDiameter / 2);
				this.innerOffset = (this.gridLength / (2 * this.gridSize) - this.innerDiameter / 2);
				this.arrowPointRadius = (int) (0.9D * (this.middleDiameter / 2.0D));
				this.arrowBaseRadius = (int) (0.6D * (this.middleDiameter / 2.0D));
				this.arrowBaseHalfLength = (int) (0.3D * (this.middleDiameter / 2.0D));
				this.pathPaint.setStrokeWidth(this.innerDiameter);
				this.pathPaint.setStrokeCap(Paint.Cap.ROUND);
				for (int row = 0;;) {
					if (row >= this.gridSize) {
//						Debug("updateDrawableNodes end");
						return;
					}
					for (int column = 0;; column++) {
//						Debug("row: " + row + " column: " + column);
						if (column >= this.gridSize) {
							row++;
							break;
						}
						int j = column * this.gridLength / this.gridSize;
						int m = row * this.gridLength / this.gridSize;
						this.outerCircles[(column + row * this.gridSize)].setBounds(
								j + this.outerOffset, 
								m + this.outerOffset, 
								j + this.outerOffset + this.outerDiameter, 
								m + this.outerOffset + this.outerDiameter);
						this.middleCircles[(column + row * this.gridSize)].setBounds(j
								+ this.middleOffset, m + this.middleOffset, j
								+ this.middleOffset + this.middleDiameter, m
								+ this.middleOffset + this.middleDiameter);
						this.innerCircles[(column + row * this.gridSize)].setBounds(j
								+ this.innerOffset, m + this.innerOffset, j
								+ this.innerOffset + this.innerDiameter, m
								+ this.innerOffset + this.innerDiameter);
					}
				}
			}

			this.outerCircles[i] = new ShapeDrawable(new OvalShape());
			this.outerCircles[i].getPaint().setColor(-6710887);
			this.middleCircles[i] = new ShapeDrawable(new OvalShape());
			this.middleCircles[i].getPaint().setColor(-16777216);
			this.innerCircles[i] = new ShapeDrawable(new OvalShape());
			this.innerCircles[i].getPaint().setColor(-1);
		}
		
	}
	
}
